require('jquery');
import _ from 'underscore';
import $ from 'jquery';
import {
    getPercent
} from './math.js';



export const ajax_call = function (url, data, method, extra_options) {
    var data = data || {};
    var method = method || 'GET';

    var options = {
        url: url,
        data: data,
        method: method,
        dataType: 'json',
        cache: false
    };
    if (['POST', 'PUT', 'PATCH'].includes(method)) {
        options.contentType = "application/json; charset=UTF-8";
        options.processData = false;
    }
    _.extend(options, extra_options);
    if (
        (['POST', 'PUT', 'PATCH'].includes(method)) &&
        options.contentType &&
        options.contentType.startsWith('application/json')
    ) {
        options.data = JSON.stringify(data);
    }
    return $.ajax(options);
};

export const updateSelectOptions = function (options, val, key) {
    /*
     * Add the selected attr to the option with value 'val'
     *
     * :param list options: list of js objects
     * :param list val: key or keys that will receive selected: true
     * :param str key: the key used to identifiy items ('value' by default)
     * :returns: True if a default or an existing value has been found
     * :rtype: bool
     */
    if (_.isUndefined(options)) {
        console.error("updateSelectOptions : options are undefined");
    }
    if (_.isUndefined(val)) {
        console.warn("updateSelectOptions : value is undefined");
        return false;
    }
    if (!_.isArray(val)) {
        val = [val];
    }
    if (_.isUndefined(key)) {
        key = 'value';
    }
    var has_selected = false;
    _.each(options, function (option) {
        delete option['selected'];
        // On checke si une des valeurs val est égal à option[key] ou à sa
        // représentation en str
        if (_.contains(val, option[key]) || _.contains(val, String(option[key]))) {

            option['selected'] = 'true';
            has_selected = true;
        }
    });
    if (!has_selected) {
        var option = getDefaultItem(options);
        if (!_.isUndefined(option)) {
            option['selected'] = true;
            has_selected = true;
        }
    }
    return has_selected;
}
export const getDefaultItem = function (items) {
    /*
     * Get The default item from an array of items looking for a default key
     *
     * :param list items: list of objects
     * :rtype: obj or undefined
     */
    var result = _.find(items, function (item) {
        return item.default == true
    });
    return result;
}
export const findCurrentSelected = function (options, current_value, key) {
    /*
     * Return the full object definition from options matching the current value
     *
     * :param list options: List of objects
     * :param str current_value: The current value in int or str
     * :param str key: The key used to identify objects (value by default)
     * :returns: The object matching the current_value
     */
    return _.find(
        options,
        function (item) {
            return item[key] == current_value
        }
    );
}
export const getOpt = function (obj, key, default_val) {
    /*
     * Helper to get a default option
     *
     * :param obj obj: The object with the getOption func
     * :param str key: The key we're looking for
     * :param default_val: the default value
     *
     * :returns: The value matching key or default
     */
    var val = obj.getOption(key);
    if (_.isUndefined(val)) {
        val = default_val
    }
    return val;
}
export const serializeForm = function (form_object, options) {
    /*
     * Return the form datas as an object
     * :param obj form_object: A jquery instance wrapping the form
     * :param dict options: One of the available options listed below
     *
     *  clean
     *
     *      Remove null values ('', null ...)
     */
    const null_values = ['', null, 'None', 'none'];
    options = options || {};

    var result = {};
    var serial = form_object.serializeArray();

    // initialize multi-valued field as arrays
    let multiValued = form_object.find('[multiple]').toArray().map(x => x.name);
    for (let fieldName of multiValued) {
        result[fieldName] = [];
    }
    $.each(serial, function () {
        if ((!options['clean']) || (_.indexOf(null_values, this.value) == -1)) {
            if (result[this.name]) {
                if (!_.isArray(result[this.name])) {
                    result[this.name] = [result[this.name]];
                }
                result[this.name].push(this.value || '');
            } else {
                result[this.name] = this.value || '';
            }
        }
    });

    form_object.find('input[type=checkbox]:not(:checked):not([multiple])').map(
        function () {
            result[this.name] = '0';
        }
    )

    return result;
}

export const handleJsonRedirect = (xhr) => {
    /**
     * Handle json redirect method.
     */
    const json_resp = xhr.responseJSON;
    if (!_.isUndefined(json_resp) && (json_resp.redirect)) {
        window.location.href = json_resp.redirect;
    }
    return xhr;
}

/** Show errors returned with a 40* http response */
export const handle400Errors = (xhr) => {
    /* 
    Minimal user feedback in case something goes wrong and is
    not handled by frontend */
    var message = "Le client a renvoyé une erreur.";
    if ((xhr.status >= 400) && (xhr.status!= 423)) {
        if (xhr.status == 415) {
            // Unsupported media type, used for upload of PDF with wrong format
            message = "Le format du fichier n'est pas supporté.";
        }else{
            message = "Votre document n'est pas valide, merci de vérifier votre saisie.";
        }
        if (xhr.responseJSON.errors) {
            message += "\n\n"
            if (_.isArray(xhr.responseJSON.errors)) {
                xhr.responseJSON.errors.forEach(function (error) {
                    message += error + "\n"
                });
            } else if (_.isObject(xhr.responseJSON.errors)) {
                Object.keys(xhr.responseJSON.errors).forEach(
                    (key) => {
                        const error = xhr.responseJSON.errors[key];
                        
                        message += key + ":";
                        
                        message += error + "\n"
                    })
                
            } else if (_.isString(xhr.responseJSON.errors)) {
                message += xhr.responseJSON.errors + "\n"
            }
        }else{
            if (xhr.responseJSON.message) {
                message += xhr.responseJSON.message
            }
        }
    }
    window.alert(message);
    hideLoader();
    return xhr
}

export const setupAjaxCallbacks = function () {
    /*
     * Setup ajax calls callbacks
     *
     * if 'redirect' is found in the json resp, we go there
     *
     * if status code is 401 : we redirect to #login
     *
     * alert() user if a 400/500 is returned.
     */
    $(document).ajaxComplete(
        function (event, xhr, settings) {
            if (xhr.status == 401) {
                hideLoader();
                window.location.replace('#login');
            } else if (xhr.status >= 500) {
                hideLoader();
                window.alert("Une erreur bloquante est survenue, veuillez réessayer ultérieurement. Si le problème persiste, veuillez contacter un administrateur.");
            } else if ((xhr.status >= 400)) { 
                handle400Errors(xhr);
            } else if (xhr.status == 0) {
                hideLoader();
                window.alert("Une erreur inconnue est survenue, veuillez réessayer ultérieurement. Si le problème persiste, veuillez contacter un administrateur.");
            } else {
                handleJsonRedirect(xhr);
            }
        }
    );
}

export const setupAjaxCSRF = function (csrfToken) {
    $.ajaxSetup({
        beforeSend: function (xhr, settings) {
            if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
                // Only send the token to relative URLs i.e. locally.
                xhr.setRequestHeader(
                    "X-CSRFToken",
                    csrfToken
                );
            }
        }
    });
};

export const setupDeferredExceptionHandling = function () {
    /* Override default jQuery exception handling inside Promises
     *
     * jQuery >3.x swalows exception happening inside promises (and issue a console.warn for some of them)
     *
     * Here we let them crash the app with a clear error and stacktrace.
     */
    jQuery.Deferred.exceptionHook = function (error, stack) {
        console.warn('re-throwing a deferred exception, otherwise, it gets (sometimes silently) discarded');
        throw error;
    };
}

export const showLoader = function () {
    /*
     * Show a loading box
     */
    $('#loading-box').show();
}
export const hideLoader = function () {
    /*
     * Show a loading box
     */
    $('#loading-box').hide();
}
export const showBtnLoader = function (jquery_object) {
    jquery_object.addClass('loader');
    jquery_object.append(
        "<span class='loading_box'><svg><use href='../static/icons/endi.svg#circle-notch'></use></svg></span>"
    );
}
export const hideBtnLoader = function (jquery_object) {
    jquery_object.removeClass('loader');
    jquery_object.find('.loading_box').remove();

}

function openPopup(url, callback) {
    var screen_width = screen.width;
    var screen_height = screen.height;
    var width = getPercent(screen_width, 60);
    var height = getPercent(screen_height, 60);
    var uniq_id = _.uniqueId('popup');
    if (_.indexOf(url, '?') != -1) {
        url = url + "&popup=" + uniq_id;
    } else {
        url = url + "?popup=" + uniq_id;
    }

    var new_win = window.open(
        url,
        uniq_id,
        "width=" + width + ",height=" + height
    );
    if (!_.isUndefined(callback)) {
        window.popupCallbacks[uniq_id] = callback;
    }
}

function dismissPopup(win, options) {
    var callback = window.popupCallbacks[win.name];
    if (!_.isUndefined(callback)) {
        callback(options);
        delete window.popupCallbacks[win.name];
    } else {
        var default_options = {
            refresh: true
        };
        _.extend(default_options, options);
        if (!_.isUndefined(default_options.force_reload)) {
            window.location.reload();
        } else {
            var new_content = "";

            if (!_.isUndefined(default_options.message)) {
                new_content += "<div class='alert alert-success'><span class='icon'><svg><use href='/static/icons/endi.svg#success'></use></svg></span> ";
                new_content += default_options.message;
            } else if (!_.isUndefined(default_options.error)) {
                new_content += "<div class='alert alert-danger'><span class='icon'><svg><use href='/static/icons/endi.svg#danger'></use></svg></span> ";
                new_content += default_options.error;
            }

            if (default_options.refresh) {
                new_content += "&nbsp;<a href='#' onclick='window.location.reload();'><span class='icon'><svg><use href='/static/icons/endi.svg#redo-alt'></use></svg></span> Rafraîchir</a>";
            }

            new_content += '</div>';
            var dest_tag = $('#popupmessage');
            if (dest_tag.length == 0) {
                dest_tag = $('.pagetitle');
            }
            dest_tag.after(new_content);
        }
    }

    win.close();
}

export const attachTools = function () {
    window.dismissPopup = dismissPopup;
    window.openPopup = openPopup;
    window.popupCallbacks = {};
}
export const scrollTop = function (value) {
    value = value || 0;
    $('#target_content').scrollTop(value);
}

export const openModal = function (jquery_object) {
    jquery_object.css('display', 'flex');
    jquery_object.addClass('appear');
    jquery_object.removeClass('dismiss');
    document.body.classList.add('modal_open');
    let modalCloseButton = jquery_object.querySelector( "button.unstyled.close" );
    modalCloseButton.focus();
}

export const closeModal = function (jquery_object) {
    jquery_object.css('display', 'none');
    jquery_object.removeClass('appear');
    jquery_object.addClass('dismiss');
    document.body.classList.remove('modal_open');
}

export const toggleModal = function (jquery_object) {
    if (jquery_object.is(':visible')) {
        closeModal(jquery_object);
    } else {
        openModal(jquery_object);
    }
}

export const sortCollection = function (collection, sortBy, direction) {
    collection.comparator = function (item1, item2) {
        if (direction === "desc") {
            return item1.get(sortBy) > item2.get(sortBy) ? -1 : 1;
        }
        return item1.get(sortBy) > item2.get(sortBy) ? 1 : -1;
    }
    collection.sort();
};
